<template><div><p>本文档最新版为 <a href="https://learnku.com/docs/laravel/10.x" target="_blank" rel="noopener noreferrer">10.x</a>，旧版本可能放弃维护，推荐阅读最新版！</p>
<h2 id="api-认证" tabindex="-1"><a class="header-anchor" href="#api-认证"><span>API 认证</span></a></h2>
<ul>
<li><a href="#introduction">简介</a></li>
<li><a href="#configuration">配置</a>
<ul>
<li><a href="#database-preparation">数据库迁移</a></li>
</ul>
</li>
<li><a href="#generating-tokens">令牌生成</a>
<ul>
<li><a href="#hashing-tokens">哈希令牌</a></li>
</ul>
</li>
<li><a href="#protecting-routes">路由保护</a></li>
<li><a href="#passing-tokens-in-requests">请求中传递令牌</a></li>
</ul>
<h2 id="简介" tabindex="-1"><a class="header-anchor" href="#简介"><span>简介</span></a></h2>
<p>默认情况下，Laravel 为 API 认证提供了一个简单的解决方案，它通过一个随机令牌分配给应用程序的每个用户。在你的 <code v-pre>config/auth.php</code> 配置文件中，已经定义了一个使用 <code v-pre>token</code> 驱动的 <code v-pre>api</code> 看守器。 这个驱动程序负责检查传入请求上的 API 令牌，并验证它是否匹配数据库中用户分配的令牌。</p>
<blockquote>
<p><strong>注意</strong>: 虽然 Laravel 附带了一个简单的基于令牌的身份验证保护，但我们强烈建议您考虑 <a href="https://learnku.com/docs/laravel/6.x/passport" target="_blank" rel="noopener noreferrer">Laravel Passport</a> 来实现提供 API 身份验证的健壮的生产应用程序。</p>
</blockquote>
<h2 id="配置" tabindex="-1"><a class="header-anchor" href="#配置"><span>配置</span></a></h2>
<h3 id="数据库准备" tabindex="-1"><a class="header-anchor" href="#数据库准备"><span>数据库准备</span></a></h3>
<p>在使用 <code v-pre>token</code> 驱动程序之前，你需要 <a href="https://learnku.com/docs/laravel/6.x/migrations" target="_blank" rel="noopener noreferrer">创建一个迁移</a> 它会在你的 <code v-pre>users</code> 表中添加一个 <code v-pre>api_token</code> 列：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Schema</span><span class="token operator">::</span><span class="token function">table</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'users'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token variable">$table</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$table</span><span class="token operator">-></span><span class="token keyword type-declaration">string</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'api_token'</span><span class="token punctuation">,</span> <span class="token number">80</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">after</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'password'</span><span class="token punctuation">)</span></span>
<span class="line">                        <span class="token operator">-></span><span class="token function">unique</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">                        <span class="token operator">-></span><span class="token function">nullable</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">                        <span class="token operator">-></span><span class="token function">default</span><span class="token punctuation">(</span><span class="token constant">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>迁移创建后，运行 migrate Artisan 命令。</p>
<blockquote>
<p>Tip：如果你选择使用不同的字段名，请确保更新了配置文件 <code v-pre>config/auth.php</code> 中的 <code v-pre>storage_key</code> 配置项。</p>
</blockquote>
<h2 id="令牌生成" tabindex="-1"><a class="header-anchor" href="#令牌生成"><span>令牌生成</span></a></h2>
<p>将 <code v-pre>api_token</code> 列添加到你的 <code v-pre>users</code> 表之后，你可以将随机 API 令牌分配给应用程序中的每个用户。 在注册期间创建 <code v-pre>User</code> 模型时，应该分配这些令牌。 如果你使用的是 <code v-pre>laravel/ui</code> 拓展包提供的 <a href="https://learnku.com/docs/laravel/6.x/authentication#authentication-quickstart" target="_blank" rel="noopener noreferrer">认证脚手架</a> ，该操作可以在 <code v-pre>RegisterController</code> 控制器的 <code v-pre>create</code> 方法中完成：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Hash</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Str</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 在有效注册之后创建一个新用户实例</span>
<span class="line"> *</span>
<span class="line"> * <span class="token keyword">@param</span>  <span class="token class-name"><span class="token keyword">array</span></span>  <span class="token parameter">$data</span></span>
<span class="line"> * <span class="token keyword">@return</span> <span class="token class-name"><span class="token punctuation">\</span>App<span class="token punctuation">\</span>User</span></span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">protected</span> <span class="token keyword">function</span> <span class="token function-definition function">create</span><span class="token punctuation">(</span><span class="token keyword type-hint">array</span> <span class="token variable">$data</span><span class="token punctuation">)</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'name'</span> <span class="token operator">=></span> <span class="token variable">$data</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'name'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token string single-quoted-string">'email'</span> <span class="token operator">=></span> <span class="token variable">$data</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'email'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token string single-quoted-string">'password'</span> <span class="token operator">=></span> <span class="token class-name static-context">Hash</span><span class="token operator">::</span><span class="token function">make</span><span class="token punctuation">(</span><span class="token variable">$data</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'password'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token string single-quoted-string">'api_token'</span> <span class="token operator">=></span> <span class="token class-name static-context">Str</span><span class="token operator">::</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token number">60</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="哈希令牌" tabindex="-1"><a class="header-anchor" href="#哈希令牌"><span>哈希令牌</span></a></h3>
<p>在上面的示例中，API 令牌以纯文本形式存储在数据库中。 如果你想使用 SHA-256 哈希算法来散列你的 API 令牌，你可以将 <code v-pre>api</code> 配置的 <code v-pre>hash</code> 选项设置为<code v-pre>true</code> 。 <code v-pre>api</code> 在你的 <code v-pre>config/auth.php</code> 配置文件中定义：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token string single-quoted-string">'api'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'driver'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'token'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'provider'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'users'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'hash'</span> <span class="token operator">=></span> <span class="token constant boolean">true</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="生成哈希标记" tabindex="-1"><a class="header-anchor" href="#生成哈希标记"><span>生成哈希标记</span></a></h4>
<p>使用散列 API 令牌时，你不应在用户注册期间生成 API 令牌。 取而代之，你需要在应用程序中实现自己的 API 令牌管理页面。 这个页面应允许用户初始化和刷新其 API 令牌。 当用户发出初始化或刷新其令牌的请求时，你应该在数据库中存储令牌的哈希副本，并将令牌的纯文本副本返回到视图/前端客户端以进行一次性显示。</p>
<p>例如，为给定用户初始化/刷新令牌并将纯文本令牌作为JSON响应返回的控制器方法如下所示：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Str</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">ApiTokenController</span> <span class="token keyword">extends</span> <span class="token class-name">Controller</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 更新认证用户的 API 令牌。</span>
<span class="line">     *</span>
<span class="line">     * <span class="token keyword">@param</span>  <span class="token class-name"><span class="token punctuation">\</span>Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span>  <span class="token parameter">$request</span></span>
<span class="line">     * <span class="token keyword">@return</span> <span class="token class-name"><span class="token keyword">array</span></span></span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token variable">$token</span> <span class="token operator">=</span> <span class="token class-name static-context">Str</span><span class="token operator">::</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token number">60</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">forceFill</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">            <span class="token string single-quoted-string">'api_token'</span> <span class="token operator">=></span> <span class="token function">hash</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'sha256'</span><span class="token punctuation">,</span> <span class="token variable">$token</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">save</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'token'</span> <span class="token operator">=></span> <span class="token variable">$token</span><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p>{注} 由于上面例子中， API 令牌有足够的熵（熵的概念是由德国物理学家克劳修斯于1865年所提出。最初是用来描述 “能量退化” 的物质状态参数之一，在热力学中有广泛的应用），创建「彩虹表」来暴力查找哈希令牌的原始值基本是徒劳的，所以也就不需要使用类似于 <code v-pre>bcrypt</code> 这种哈希方法。</p>
</blockquote>
<h2 id="路由保护" tabindex="-1"><a class="header-anchor" href="#路由保护"><span>路由保护</span></a></h2>
<p>Laravel 包含一个 <a href="https://learnku.com/docs/laravel/6.x/authentication#adding-custom-guards" target="_blank" rel="noopener noreferrer">身份认证看守器</a> 可以自动验证传入请求的 API 令牌。 你只需要在任何需要有效访问令牌的路由上指定 <code v-pre>auth:api</code> 中间件：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">middleware</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'auth:api'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/user'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="请求中传递令牌" tabindex="-1"><a class="header-anchor" href="#请求中传递令牌"><span>请求中传递令牌</span></a></h2>
<p>有几种方法可以将 API 令牌传递给你的应用程序。 我们将在使用 Guzzle HTTP 库演示其用法时去讨论这些方法。 你可以根据应用程序的需要选择其中的任何方法。</p>
<h4 id="请求参数" tabindex="-1"><a class="header-anchor" href="#请求参数"><span>请求参数</span></a></h4>
<p>你的应用程序的 API 使用者可以将其令牌作为 <code v-pre>api_token</code> 查询字符串值：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$response</span> <span class="token operator">=</span> <span class="token variable">$client</span><span class="token operator">-></span><span class="token function">request</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'GET'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'/api/user?api_token='</span><span class="token operator">.</span><span class="token variable">$token</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h4 id="请求负载" tabindex="-1"><a class="header-anchor" href="#请求负载"><span>请求负载</span></a></h4>
<p>应用程序的 API 使用者可以在请求的表单参数中以 <code v-pre>api_token</code> 的形式包含其 API 令牌：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$response</span> <span class="token operator">=</span> <span class="token variable">$client</span><span class="token operator">-></span><span class="token function">request</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'POST'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'/api/user'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'headers'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'Accept'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'application/json'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'form_params'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'api_token'</span> <span class="token operator">=></span> <span class="token variable">$token</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="bearer-令牌" tabindex="-1"><a class="header-anchor" href="#bearer-令牌"><span>Bearer 令牌</span></a></h4>
<p>应用程序的 API 使用者可以在请求的 <code v-pre>Authorization</code> 头中提供其 API 令牌作为 <code v-pre>Bearer</code> 令牌:</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$response</span> <span class="token operator">=</span> <span class="token variable">$client</span><span class="token operator">-></span><span class="token function">request</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'POST'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'/api/user'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'headers'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'Authorization'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'Bearer '</span><span class="token operator">.</span><span class="token variable">$token</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token string single-quoted-string">'Accept'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'application/json'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p>本译文仅用于学习和交流目的，转载请务必注明文章译者、出处、和本文链接<br>
我们的翻译工作遵照 <a href="https://learnku.com/docs/guide/cc4.0/6589" target="_blank" rel="noopener noreferrer">CC 协议</a>，如果我们的工作有侵犯到您的权益，请及时联系我们。</p>
</blockquote>
<hr>
<blockquote>
<p>原文地址：<a href="https://learnku.com/docs/laravel/6.x/api-authentication/5429" target="_blank" rel="noopener noreferrer">https://learnku.com/docs/laravel/6.x/api...</a></p>
<p>译文地址：<a href="https://learnku.com/docs/laravel/6.x/api-authentication/5429" target="_blank" rel="noopener noreferrer">https://learnku.com/docs/laravel/6.x/api...</a></p>
</blockquote>
</div></template>


